package com.isp.common.utils;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;

/**
 * AES工具
 *
 * @author linsy
 * @created 2024/3/11
 */
public class AesUtils {

    private static String generateRandomString(int length) {
        // 字符串中可能包含的字符集
        String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

        // 使用SecureRandom生成随机数
        SecureRandom secureRandom = new SecureRandom();

        // 使用StringBuilder构建字符串
        StringBuilder stringBuilder = new StringBuilder(length);

        for (int i = 0; i < length; i++) {
            // 生成一个随机索引
            int randomIndex = secureRandom.nextInt(characters.length());

            // 从字符集中获取字符并追加到字符串构建器
            char randomChar = characters.charAt(randomIndex);
            stringBuilder.append(randomChar);
        }

        return stringBuilder.toString();
    }

    private static SecretKey generateRandomKey() throws Exception {
        SecureRandom secureRandom = new SecureRandom();
        byte[] keyData = new byte[32]; // 256 bits
        secureRandom.nextBytes(keyData);
        return new SecretKeySpec(keyData, "AES");
    }

    private static byte[] generateRandomNonce() {
        SecureRandom secureRandom = new SecureRandom();
        byte[] nonce = new byte[12]; // 96 bits
        secureRandom.nextBytes(nonce);
        return nonce;
    }

    private static byte[] encrypt(String plainText, String secretKey, byte[] nonce, String associatedData) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");

        GCMParameterSpec parameterSpec = new GCMParameterSpec(128, nonce);
        SecretKeySpec key = new SecretKeySpec(secretKey.getBytes(), "AES");

        cipher.init(Cipher.ENCRYPT_MODE, key, parameterSpec);

        // 设置关联数据
        cipher.updateAAD(associatedData.getBytes(StandardCharsets.UTF_8));

        byte[] plainTextBytes = plainText.getBytes(StandardCharsets.UTF_8);

        // 返回密文
        return cipher.doFinal(plainTextBytes);
    }

    private static String decryptToString(byte[] associatedData, String secretKey, byte[] nonce, String cipherText) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");

        GCMParameterSpec parameterSpec = new GCMParameterSpec(128, nonce);
        SecretKeySpec key = new SecretKeySpec(secretKey.getBytes(), "AES");

        cipher.init(Cipher.DECRYPT_MODE, key, parameterSpec);

        // 设置关联数据
        cipher.updateAAD(associatedData);

        // 解密
        byte[] decryptedTextBytes = cipher.doFinal(Base64.getDecoder().decode(cipherText));

        return new String(decryptedTextBytes, StandardCharsets.UTF_8);
    }

    public static void main(String[] args) throws Exception {
        // 生成随机256位密钥
        SecretKey secretKey = generateRandomKey();
        System.out.println(Base64.getEncoder().encodeToString(secretKey.getEncoded()));


        // 明文
        String plainText = "[{\"position\":\"0 0 0\",\"uuid\":\"1\",\"rotation\":\"0 0 0\",\"type\":\"image\",\"subType\":\"static\",\"scale\":\"1 1 1\",\"width\":288,\"height\":648,\"depth\":0,\"linkUrl\":\"http://192.168.0.201:9090/develop/product/quick-ar/tmp_33f3f20a928b74862504cff8ba4f6fea2fa114e6e9a55618-1701853426009.mp4\",\"originData\":{\"width\":850,\"height\":850,\"depth\":0},\"fillType\":\"auto\"}]";

        // 生成随机nonce
        byte[] nonce = generateRandomNonce();
        String s = Base64.getEncoder().encodeToString(nonce);
        System.out.println("nonce：" + s);

        // 关联数据
        String associatedData = "Some additional data";
        String s1 = generateRandomString(32);
        System.out.println("secretKey：" + s1);

        // 加密
        byte[] cipherText = encrypt(plainText, s1, s.getBytes(), associatedData);

        // 解密
        String decryptedText = decryptToString(associatedData.getBytes(), s1, s.getBytes(), Base64.getEncoder().encodeToString(cipherText));

        // 打印结果
        System.out.println("Original Text: " + plainText);
        System.out.println("Encrypted Text: " + Base64.getEncoder().encodeToString(cipherText));
        System.out.println("Decrypted Text: " + decryptedText);
    }

}
